home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Leser 15
/
Amiga Plus Leser CD 15.iso
/
Scene
/
Eurochart44
/
Articles
/
The256-ByteIntro.txt
< prev
next >
Wrap
Text File
|
2002-03-12
|
16KB
|
590 lines
»CL6:--------------------------------------------------------------------------------
»CL0: The 256-Byte Intro
»CL6:--------------------------------------------------------------------------------
Written by »CL5:Dr. Doom »CL6:of »CL5:IRIS
»CL1:Boredom can be a very inspiring thing.
And so it was that one day I was
feeling extremely bored. Having just
(sort of) survived the exhausting
trial of piecing together an issue of
the Eurochart, »CL8:I was more or less
prepared to swallow my own tongue
rather than look at another piece of
code for a long, long time. »CL1:Protracker
had pissed me off earlier that day
with its "spontaneous crash" feature,
and PPaint hadn't really appealed to
me since I downgraded to 030. No
matter how hard I kicked my TV set,
it'd only produce predictable American
sitcoms and creepy soaps. »CL7:My music
collection was as humble as ever, and
I wasn't in the mood for music anyway.
»CL1:And of course no vodka, no beer, no
horny nurses knocking on my door,
nothing.
- What a predicament, huh?
Luckily, I'd recently expanded my
collection of scene productions, and
watching a few of them sounded like
the perfect remedy for my particular
problem. Listing the directories
alphabetically somehow lead me into
the "4k Intros" directory first. Yeah,
go figure. Now, since no group has
ever decided to call itself "Aaabbc",
Apathy appeared under my mouse
pointer. A swift double-click led me
further down the tree and there I was
confronted with no less than one
directory. Hmm. "2k Is Too Much!", the
greenish white shouted at my eyes.
Well, I guess it is. Twice more I
clicked.
»CL8:Suddenly, something caught my
attention and I snapped out of my
boredom-induced semitrance.»CL1: In this
directory were three files. A readme,
a .info file, and a third file which
had to be the executable. »CL7:What caught
my attention was the fact that this
third file was nowhere near 2k in
size. 256 bytes was all it amounted
to.»CL1: My own non-system startup alone
was some 300 bytes (and my system
startup about a million times that),
and if this was actually an intro,
here was quite an accomplishment
staring me in the face. Without
further hesitation I doubleclicked and
poof! - »CL6:My workbench turned into a
starfield with the message "Zeeball of
Apathy, 256 bytes" printed in the
corner. Wow.»CL1:
In a heartbeat, coder's instinct
took over (yes, there IS such a
thing). What was going on here? Was
this an Intuition screen? Nope,
Amiga+M did nothing. Surely, Zeeball
couldn't have disabled input handling
in 256 bytes AND opened a screen AND
rendered a starfield. No, it appeared
to be a system killer. But so
small? I quit the intro and was even
more amazed to find my system running
perfectly. Obviously the system
startup was not only tiny but also
safe.
»CL8:Now, I'm not usually one to resource
other people's code, and this would be
no exception.»CL1: However, I couldn't
resist the temptation to load up the
Barfly Debugger and have a little
look. Click-click-click, and the
DissWindow appeared. Looking briefly
at the code, puzzled started to take
the place of astonished. This was no
startup routine at all. Certainly
wasn't a decruncher, and it wasn't
even an icon startup even though the
intro came equipped with an icon. Odd.
I turned to the readme file. "Don't
rename the executable!", it said.
»CL7:I renamed the executable (well what
did you expect when you specifically
tell me not to?). It crashed. I
renamed it back. It worked.»CL1: I then
focused on the suspicious presence of
the icon. I renamed only the .info
file. It crashed. Aha! Although the
icon appeared perfectly normal from
the workbench, a hex dump showed me
otherwise. What I saw was clearly
code, strings such as
"graphics.library",0 and empty spaces
for variables. I even found the
message "Myslenie to przywilej.
Gratulacje!" which I'm guessing means
something to the effect of "Congrats,
you figured it out".
»CL6:
Apparently the executable merely
loaded the actual code hidden away in
the icon. This was brilliant.»CL1: A
genuine fake in the truest of spirits.
Thumbs up to Zeeball who has
otherwise not impressed me so far
(yes, arrogance is a registered
trademark of the IRIS Corporation, in
case you're wondering).
»CL8:Now, most coders would have merely sat
back, smiled and turned on the next
intro.»CL1: But not this one. For some
reason I was suddenly determined to
prove that this could be done without
faking. My mind shifted into sideways
and I loaded my assembler, completely
forgetting the pain and the horror it
had inflicted upon me during my weeks
of setting up the Eurochart. This
looked like a job for...
»CL8: HOW TO CODE A 256-BYTE INTRO
»CL1:The first step I took was scrapping
the traditional startupcode. Even if
madly size-optimized, it wouldn't
leave any room for an effect, or at
least not enough for a starfield. »CL7:I
wanted it to open a screen and return
to the system screen afterwards. Since
no one would watch a starfield for
more than a few seconds,»CL1: I figured
multitasking could be left on with
relative safety. It would just have to
give me a planar display to work with.
So I needed to open grapics.library,
or at least find it in memory in
order to read the pointers to
the active view and copperlist, as
well as call LoadView(null) to safely
reset the display. The traditional
approach, and the one taught in all
coders' dogma, is to open the library
through OpenLibrary() with a pointer
to the string "graphics.library". This
alone would cost me 36 bytes. No way!
»CL8:Long ago, bad coders opted to find
exec.library and then traverse the
linked list of libraries a
predetermined number of steps and then
assume that they'd found the library
they were looking for. »CL1: This was
possible for e.g. graphics.library,
because ROM libraries are always open.
I decided to explore this. It turned
out that graphics.library was library
#44 on my computer. Nice, but, just as
I'd thought a simple 10-byte loop
function might lead me to
graphics.library, a reboot later it
had moved to position 35. Obviously I
would never know where to find it. At
least not without comparing the
library name to a string, but that
would be at least as big as the
traditional approach. Curses!
Then inspiration struck (as it often
does when you're a genius). I would
make a compare function which compared
values derived from strings rather
than strings. This way I would only »PIC:3.iff»
have to save the derivative for
"graphics.library",0 and I would be
able to find the right library with
reasonable certainty. This is what I
came up with:
; find something that looks a bit like
; graphics.library (execbase is in a6)
»CL7:.loop move.l 4(a6),a6
»CL7: move.l 10(a6),a0
»CL7: move.l (a0)+,d0 »CL8:; string'
»CL7: add.l (a0)+,d0
»CL7: add.l (a0),d0
»CL7: cmp.l #"grap"+"hics"+".lib",d0 »CL8:; keep the faith
»CL7: bne.b .loop
»CL1:Now the odds of finding
graphics.library were in my favour and
this only cost me 22 bytes. I was
pretty pleased, although I still
insist such genius should be rewarded
more handsomely. Life is cruel.
The startup routine was next. I would
need to save the active view in a
register, call LoadView(null) (which
was no problem now), then set up a
lowres display of some sort. »CL8:I decided
to set up everything from a
copperlist, since I'd need to
install one anyway as the null-view
copperlist continuously disabled all
display DMA.»CL1: But where to put the
copperlist... a different section was
out of the question since the presence
of more section descriptors in the
executable was not what I needed.
Moreover, this would also involve a
relocation, and a relocation table
would add about 40 bytes, even with
only one entry. So there could only be
one section, and it would have to be
in chip memory, which is usually not a
good place to put your code, but then,
it was just a starfield. My startup
routine eventually looked like this:
»PIC:4.iff» »PIC:4.iff» »PIC:4.iff»
»CL7:section code,code_c
»CL7: .
»CL7: . (graphics.library to a6)
»CL7: .
»CL7: move.l $22(a6),d4 »CL8:; save view
»CL7: sub.l a1,a1 »CL8:; loadview(null)
»CL7: jsr -222(a6)
»CL7: lea copper(pc),a0 »CL8:; install copperlist
»CL7: move.l a0,$080(a5) »CL8:; a5 = $dff000 somehow
»CL7: .
»CL7: . (avoiding d4 here)
»CL7: .
»CL7: move.l d4,a1 »CL8: ; reload view
»CL7: jsr -222(a6)
»CL7: move.l $26(a6),$080(a5) »CL8:; restore copperlist
»CL7: rts »CL8:; the end
»CL7:; bonzai copperlist
»CL7:copper dc.w $0100,$1200 »CL8:; 1 plane, colorburst
»CL7: dc.w $0180,$0424 »CL8:; palette (purple and
»CL7: dc.w $0182,$008f »CL8:; cyan, naturally)
»CL7: dc.l -2
»CL1:I was able to reduce the copperlist to
only setting BPLCON0 and colour regs
0 and 1, because LoadView(null) had
initialised everything else for me.
Only thing missing was disabling
sprite DMA, so sprites did flicker for
the first second the intro ran, but I
left that for later, not knowing if
»CL1:there'd be room for it.
The next step was to set up a bitplane
where I might render my starfield. I
had to allocate this memory with
exec.library to avoid those nasty
relocations.
»CL7:; allocate chipmem space
»CL7: move.l 4.w,a6
»CL7: moveq #10240>>8,d0 »CL8:; give me 8000 bytes
»CL7: lsl.l #8,d0 »CL8:; and some room to play
»CL7: moveq #3,d1
»CL7: jsr -198(a6) »CL8:; allocmem()
»CL7: move.l d0,a2 »CL8:; never fails i guess
»PIC:4.iff»
»CL1:Now with my bitplane safely (?) in A2,
I was ready to play. At first I tried
to use the startup code as a data area
for my star coordinates, but it was
nowhere near big nor random enough to
give a good result. So I
initialized a table in my allocated
memory area instead.
»CL7:; initialize stars
»CL7: moveq.l #-79,d0 »CL8:; random number seed
»CL7: lea 8192(a2),a0
»CL7: move.w #128*3-1,d7
»CL7:.initloop ror.l d0,d0 »CL8:; get random number
»CL7: addq.l #7,d0
»CL7: move.w d0,(a0)+
»CL7: dbra d7,.initloop
»CL1:128 stars was the most I could use
without needing a move.w for the
second loop counter. I was worried
this would take too much space but it
had to look good as well as be tiny.
The main loop required some
consideration, as it was the largest
part of the code. It would need to
wait for the vertical blanking
»CL1:
interval, clear the screen, render and
move the stars, test for a mouse click
and loop if none occurred.
Checking the vertical beam position
turned out to be the best
(i.e. smallest) way to time the effect
»CL7:.mainloop
»CL7: .
»CL7: .
»CL7: cmp.w #$12f,5(a5) »CL8:; wait for end-of-diw
»CL7: bne.b .mainloop
»CL7:
»CL1:This left me with some time to render
before anything would be shown.
Perfect. Then for setting up and
clearing the bitplane, obviously:
»CL7: move.l a2,$0e0(a5) »CL8:; set bitplane pointer
»CL7: move.l a2,a0 »CL8:; clear bitplane
»CL7: move.w #8192/4-1,d7
»CL7:.clearloop clr.l (a0)+
»CL7: dbra d7,.clearloop
»CL1:All that was left now was the
starfield. A bit of linear algebra,
half a cigarette and one cup of
coffee later I was left with this:
»CL7: moveq #128-1,d6
»CL7:.loopstar
»CL7: movem.w (a0)+,d0-d2 »CL8: ; load (x,y,z) and extend
»CL7: subq.b #7,-2(a0) »CL8: ; old z :- 7
»CL7: bcs.b .skipstar »CL8: ; if carry, then z could
»CL8:; be zero, so skip to
»CL8:; avoid divide-by-zero
»CL7: lsr.w #7,d2 »CL8: ; force positive and
»CL8:; adjust perspective
»CL7: divs.w d2,d0 »CL8: ; do perspective thing
»CL7: divs.w d2,d1
»CL7: add.w #160,d0 »CL8:; center x and clip
»CL7: cmp.w #320,d0
»CL7: bhs.b .skipstar
»CL7: add.w #100,d1 »CL8:; center y and clip
»CL7: cmp.w #200,d1 »CL8:; i don't think there's
»CL7: bhs.b .skipstar »CL8:; a smaller way to do
»CL7: »CL8:; this, really
»CL7: muls.w #40,d1 »CL8:; plot point
»CL7: moveq #-$80,d2
»CL7: ror.b d0,d2
»CL7: lsr.w #3,d0
»CL7: add.w d0,d1
»CL7: or.b d2,(a2,d1.w)
»CL7:.skipstar
»CL7: dbra d6,.loopstar
»CL7: btst.b #2,$016(a5) »CL8:; test for rmb because
»CL7: bne.b .mainloop »CL8:; lmb is in $bfexxx
»CL7: »CL8:; and $dffxxx is in a5
»CL1:After making sure it really worked,
I assembled the thing and saved the
executable. I had done it! 240 bytes,
which was enough to let me fix the
sprite flicker problem with an
additional copper instruction and even
insert a couple of NOPs in the code to
show off.
»CL8:I'm feeling somewhat proud of myself »PIC:3.iff»
now. I know this is a small
accomplishment,»CL1: and after all, I
didn't manage to print any text on the
screen (and the starfield lacks depth
shading and so on), but I did write a
"complete" intro in just 256 bytes, a
thing that another coder had to fake
but I could do for real. I think
that's neat. Now of course I'll go
back to being bored. I don't dare
watch another 4k intro. Besides, I
think I'll leave those to the ones who
can't be bothered to size-optimize
their code.
(»CL7:You can find the uncommented
sourcecode along with the executable
somewhere in this Eurochart archive,
probably the bonus directory.»CL1:)